;   Copyright (c) 2019 Renesas Electronics Corporation. All rights reserved.
;
;   Warranty Disclaimer :
;
;   Because the Product(s) is licensed free of charge, there is no warranty of
;   any kind whatsoever and expressly disclaimed and excluded by Renesas, 
;   either expressed or implied, including but not limited to those for non-
;   infringement of intellectual property, merchantability and/or fitness for
;   the particular purpose. Renesas shall not have any obligation to maintain,
;   service or provide bug fixes for the supplied Product(s) and/or the 
;   Application.
;
;   Each User is solely responsible for determining the appropriateness of using
;   the Product(s) and assumes all risks associated with its exercise of rights
;   under this Agreement, including, but not limited to the risks and costs of
;   program errors, compliance with applicable laws, damage to
;   or loss of data, programs or equipment, and unavailability or interruption
;   of operations.
;
;   Limitation of Liability :
;
;   In no event shall Renesas be liable to the User for any incidental,
;   consequential, indirect, or punitive damage (including but not limited to
;   lost profits) regardless of whether such liability is based on breach of
;   contract, tort, strict liability, breach of warranties, failure of essential
;   purpose or otherwise and even if advised of the possibility of such damages.
;   Renesas shall not be liable for any services or products provided by third
;   party vendors, developers or consultants identified or referred to the User
;   by Renesas in connection with the Product(s) and/or the Application.
;
;-----------------------------------------------------------------------------
;   variable
;-----------------------------------------------------------------------------
    ; local ram address
    LOCAL_RAM_CPU0_ADDR         .set 0xFDC00000     ; LOCAL RAM(CPU0) start address
    LOCAL_RAM_CPU0_END          .set 0xFDC0FFFF     ; LOCAL RAM(CPU0) end address
    LOCAL_RAM_CPU1_ADDR         .set 0xFDA00000     ; LOCAL RAM(CPU1) start address
    LOCAL_RAM_CPU1_END          .set 0xFDA0FFFF     ; LOCAL RAM(CPU1) end address
    LOCAL_RAM_CPU2_ADDR         .set 0xFD800000     ; LOCAL RAM(CPU2) start address
    LOCAL_RAM_CPU2_END          .set 0xFD80FFFF     ; LOCAL RAM(CPU2) end address
    LOCAL_RAM_CPU3_ADDR         .set 0xFD600000     ; LOCAL RAM(CPU3) start address
    LOCAL_RAM_CPU3_END          .set 0xFD60FFFF     ; LOCAL RAM(CPU3) end address
    LOCAL_RAM_SELF_ADDR         .set 0xFDE00000     ; LOCAL RAM(Self) start address
    LOCAL_RAM_SELF_END          .set 0xFDE0FFFF     ; LOCAL RAM(Self) end address

    ; cluster ram address
    CLUSTER_RAM0_ADDR           .set 0xFE000000     ; CLUSTER RAM(Cluster0) start address
    CLUSTER_RAM0_END            .set 0xFE07FFFF     ; CLUSTER RAM(Cluster0) end address
    CLUSTER_RAM0_ADDR0          .set 0xFE000000     ; CLUSTER RAM(Cluster0) start address0
    CLUSTER_RAM0_END0           .set 0xFE03FFFF     ; CLUSTER RAM(Cluster0) end address0
    CLUSTER_RAM0_ADDR1          .set 0xFE040000     ; CLUSTER RAM(Cluster0) start address1
    CLUSTER_RAM0_END1           .set 0xFE07FFFF     ; CLUSTER RAM(Cluster0) end address1

    CLUSTER_RAM1_ADDR           .set 0xFE100000     ; CLUSTER RAM(Cluster1) start address
    CLUSTER_RAM1_END            .set 0xFE17FFFF     ; CLUSTER RAM(Cluster1) end address
    CLUSTER_RAM1_ADDR2          .set 0xFE100000     ; CLUSTER RAM(Cluster1) start address2
    CLUSTER_RAM1_END2           .set 0xFE13FFFF     ; CLUSTER RAM(Cluster1) end address2
    CLUSTER_RAM1_ADDR3          .set 0xFE140000     ; CLUSTER RAM(Cluster1) start address3
    CLUSTER_RAM1_END3           .set 0xFE17FFFF     ; CLUSTER RAM(Cluster1) end address3

    CLUSTER_RAM2_ADDR           .set 0xFE400000     ; CLUSTER RAM(Cluster2) start address
    CLUSTER_RAM2_END            .set 0xFE5FFFFF     ; CLUSTER RAM(Cluster2) end address
    CLUSTER_RAM2_ADDR0          .set 0xFE400000     ; CLUSTER RAM(Cluster2) start address0
    CLUSTER_RAM2_END0           .set 0xFE47FFFF     ; CLUSTER RAM(Cluster2) end address0
    CLUSTER_RAM2_ADDR1          .set 0xFE480000     ; CLUSTER RAM(Cluster2) start address1
    CLUSTER_RAM2_END1           .set 0xFE4FFFFF     ; CLUSTER RAM(Cluster2) end address1
    CLUSTER_RAM2_ADDR2          .set 0xFE500000     ; CLUSTER RAM(Cluster2) start address2
    CLUSTER_RAM2_END2           .set 0xFE57FFFF     ; CLUSTER RAM(Cluster2) end address2
    CLUSTER_RAM2_ADDR3          .set 0xFE580000     ; CLUSTER RAM(Cluster2) start address3
    CLUSTER_RAM2_END3           .set 0xFE5FFFFF     ; CLUSTER RAM(Cluster2) end address3

    CLUSTER_RAM3_ADDR           .set 0xFE800000     ; CLUSTER RAM(Cluster3) start address
    CLUSTER_RAM3_END            .set 0xFE83FFFF     ; CLUSTER RAM(Cluster3) end address
    CLUSTER_RAM3_ADDR0          .set 0xFE800000     ; CLUSTER RAM(Cluster3) start address0
    CLUSTER_RAM3_END0           .set 0xFE80FFFF     ; CLUSTER RAM(Cluster3) end address0
    CLUSTER_RAM3_ADDR1          .set 0xFE810000     ; CLUSTER RAM(Cluster3) start address1
    CLUSTER_RAM3_END1           .set 0xFE81FFFF     ; CLUSTER RAM(Cluster3) end address1
    CLUSTER_RAM3_ADDR2          .set 0xFE820000     ; CLUSTER RAM(Cluster3) start address2
    CLUSTER_RAM3_END2           .set 0xFE82FFFF     ; CLUSTER RAM(Cluster3) end address2
    CLUSTER_RAM3_ADDR3          .set 0xFE830000     ; CLUSTER RAM(Cluster3) start address3
    CLUSTER_RAM3_END3           .set 0xFE83FFFF     ; CLUSTER RAM(Cluster3) end address3

    ; flag status
    FLAG_ON                     .set 1
    FLAG_OFF                    .set 0

    ; using eiint as table reference method
    USE_TABLE_REFERENCE_METHOD  .set FLAG_ON

    ; offset of processing module setting table element
    .OFFSET_ENTRY               .set FLAG_OFF

    ; enable clock gearup
    ENABLE_CLOCK_GEARUP         .set FLAG_ON        ; enable clock gearup

    ; enable module standby register set
    ENABLE_MODULE_STANDBY_SET   .set FLAG_OFF       ; enable module standby register set

    ; enable PEX by PE0
    ENABLE_PE1_BY_PE0           .set FLAG_ON        ; enable PE1 by PE0
    ENABLE_PE2_BY_PE0           .set FLAG_OFF        ; enable PE2 by PE0
    ENABLE_PE3_BY_PE0           .set FLAG_OFF        ; enable PE3 by PE0

    ; target dependence informations (specify values suitable to your system)
    MEV_ADDR                    .set CLUSTER_RAM2_ADDR  ; cluster RAM data Address

;-----------------------------------------------------------------------------
;   __start
;-----------------------------------------------------------------------------
    .section    ".text", text
    .public    __start
    .align    4
__start:

    ;--------------------------------
    ; Register Initialization
    ;--------------------------------

    ;- General purpose register
    $nowarning
    mov     r0, r1          ; r1  Assembler reserved register
    $warning
    mov     r0, r2          ; r2  Register for address and data variables
    mov     r0, r3          ; r3  Stack pointer(SP)
    mov     r0, r4          ; r4  Global pointer(GP)
    mov     r0, r5          ; r5  Text pointer(TP)
    mov     r0, r6          ; r6  Register for addresses and data variables
    mov     r0, r7          ; r7  Register for addresses and data variables
    mov     r0, r8          ; r8  Register for addresses and data variables
    mov     r0, r9          ; r9  Register for addresses and data variables
    mov     r0, r10         ; r10 Register for addresses and data variables
    mov     r0, r11         ; r11 Register for addresses and data variables
    mov     r0, r12         ; r12 Register for addresses and data variables
    mov     r0, r13         ; r13 Register for addresses and data variables
    mov     r0, r14         ; r14 Register for addresses and data variables
    mov     r0, r15         ; r15 Register for addresses and data variables
    mov     r0, r16         ; r16 Register for addresses and data variables
    mov     r0, r17         ; r17 Register for addresses and data variables
    mov     r0, r18         ; r18 Register for addresses and data variables
    mov     r0, r19         ; r19 Register for addresses and data variables
    mov     r0, r20         ; r20 Register for addresses and data variables
    mov     r0, r21         ; r21 Register for addresses and data variables
    mov     r0, r22         ; r22 Register for addresses and data variables
    mov     r0, r23         ; r23 Register for addresses and data variables
    mov     r0, r24         ; r24 Register for addresses and data variables
    mov     r0, r25         ; r25 Register for addresses and data variables
    mov     r0, r26         ; r26 Register for addresses and data variables
    mov     r0, r27         ; r27 Register for addresses and data variables
    mov     r0, r28         ; r28 Register for addresses and data variables
    mov     r0, r29         ; r29 Register for addresses and data variables
    mov     r0, r30         ; r30 Element pointer(EP)
    mov     r0, r31         ; r31 Link pointer(LP)

    ;- Basic system register
    ldsr    r0,  0, 0       ; SR0,0  EIPC
    ldsr    r0,  2, 0       ; SR2,0  FEPC
    ldsr    r0, 16, 0       ; SR16,0 CTPC
    ldsr    r0, 28, 0       ; SR28,0 EIWR
    ldsr    r0, 29, 0       ; SR29,0 FEWR
    ldsr    r0,  3, 1       ; SR3,1  EBASE
    ldsr    r0,  4, 1       ; SR4,1  INTBP
    ldsr    r0,  6, 2       ; SR6,2  MEA
    ldsr    r0,  8, 2       ; SR8,2  MEI
    ldsr    r0, 18, 2       ; SR18,2 RBIP

    ;- FPU system register
    mov     0x00010020, r10 ; set 1 in PSW.CU0 for writing FPU Function Register
                            ; set 1 in PSW.ID for prohibiting EI-level interrupt
    ldsr    r10, 5, 0       ; SR5,0  PSW 

    mov     0x00220000, r10 ; set 1 in FPSR.FS
    ldsr    r10, 6, 0       ; SR6,0  FPSR
    ldsr    r0,  7, 0       ; SR7,0  FPEPC
    ldsr    r0,  8, 0       ; SR8,0  FPST
    ldsr    r0,  9, 0       ; SR9,0  FPCC

    ;- MPU function register
    ldsr    r0,  8, 5       ; SR8,5  MCA
    ldsr    r0,  9, 5       ; SR9,5  MCS
    ldsr    r0, 11, 5       ; SR11,5 MCR
     
    mov     r0,r2	    
    _loop:		    ; Initialize MPU 32 Areas
    ldsr    r2, 16, 5       ; SR16,5 MPIDX
    ldsr    r0, 20, 5       ; SR20,5 MPLA
    ldsr    r0, 21, 5       ; SR21,5 MPUA
    ldsr    r0, 22, 5       ; SR22,5 MPAT
    add     0x1, r2         ;
    cmp     0x20, r2        ;
    bne     _loop
    
    ldsr    r0, 24, 5       ; SR24,5 MPID0
    ldsr    r0, 25, 5       ; SR25,5 MPID1
    ldsr    r0, 26, 5       ; SR26,5 MPID2
    ldsr    r0, 27, 5       ; SR27,5 MPID3
    ldsr    r0, 28, 5       ; SR28,5 MPID4
    ldsr    r0, 29, 5       ; SR29,5 MPID5
    ldsr    r0, 30, 5       ; SR30,5 MPID6
    ldsr    r0, 31, 5       ; SR31,5 MPID7
    ldsr    r0, 12, 5       ; SR12,5 MCI

    ;- Cache Operation Function Registers
    ldsr    r0, 16, 4       ; SR16,4 ICTAGL
    ldsr    r0, 17, 4       ; SR17,4 ICTAGH
    ldsr    r0, 18, 4       ; SR18,4 ICDATL
    ldsr    r0, 19, 4       ; SR19,4 ICDATH
    ldsr    r0, 28, 4       ; SR28,4 ICERR

    ;- Virtualization support function system register
    ldsr    r0, 20, 1       ; SR20,1 HVSB

    ;- Guest Context Register
    ldsr    r0,  0, 9       ; SR0,9  GMEIPC
    ldsr    r0,  2, 9       ; SR2,9  GMFEPC
    ldsr    r0, 19, 9       ; SR19,9 GMEBASE
    ldsr    r0, 20, 9       ; SR20,9 GMINTBP
    ldsr    r0, 28, 9       ; SR28,9 GMEIWR
    ldsr    r0, 29, 9       ; SR29,9 GMFEWR
    ldsr    r0,  6, 9       ; SR6,9  GMMEA
    ldsr    r0, 8, 9       ; SR8,9 GMMEI

    ;--------------------------------
    ; jump to entry point of each PE
    ;--------------------------------

    stsr    0, r10, 2               ; get PEID.PEID

    cmp     0, r10
    bz      __start_PE0             ; if PEID.PEID is 0

$if ENABLE_PE1_BY_PE0 == FLAG_ON
    cmp     1, r10
    bz      __start_PE1             ; if PEID.PEID is 1
$endif  ; ENABLE_PE1_BY_PE0

$if ENABLE_PE2_BY_PE0 == FLAG_ON
    cmp     2, r10
    bz      __start_PE2             ; if PEID.PEID is 2
$endif  ; ENABLE_PE2_BY_PE0

$if ENABLE_PE3_BY_PE0 == FLAG_ON
    cmp     3, r10
    bz      __start_PE3             ; if PEID.PEID is 3
$endif  ; ENABLE_PE3_BY_PE0

__exit:
    br      __exit

;-----------------------------------------------------------------------------
;   __start_PE0
;-----------------------------------------------------------------------------

__start_PE0:

    ; Remove the CRG of Cluster RAM 2(RAM Data Area)
;    mov     -0x5a5a5aff, r2         ; set 0xA5A5A501 in CRGKCPROT for enable writes to protected registers
;    st.w    r2, 0xFFC6D200[r0]      ; set CRGKCPROT

;    movea   0x153, r0, r2
;    st.w    r2, 0xFFC6D210[r0]

;    mov     -0x1, r2
;    st.w    r2, 0xFFC6D214[r0]

;    st.w    r0, 0xFFC6D218[r0]

;    mov     0x1fff00, r2
;    st.w    r2, 0xFFC6D21C[r0]

;    mov     -0x5a5a5b00, r2         ; set 0xA5A5A500 in CRGKCPROT for disable writes to protected registers
;    st.w    r0, 0xFFC6D200[r0]      ; set CRGKCPROT

    st.w    r0, MEV_ADDR

$if ENABLE_CLOCK_GEARUP == FLAG_ON
    jarl    _clock_gearup, lp       ; clock gearup
$endif  ; ENABLE_CLOCK_GEARUP

$if ENABLE_MODULE_STANDBY_SET == FLAG_ON
    jarl    _module_standby_set, lp ; module standby register set
$endif  ; ENABLE_MODULE_STANDBY_SET

$if ENABLE_PE1_BY_PE0 == FLAG_ON
    ld.w    0xfffb2000[r0], r10     ; get BOOTCTRL
    ori     2, r10, r11             ; set 1 in BOOTCTRL.BC1 for enabled PE1
    st.w    r11, 0xfffb2000[r0]     ; set BOOTCTRL

    mov     0x0, r2                 ; wait for 100us(0x9c40(40,000)count)
    br     .L.start_PE0.1
.L.start_PE0.0:
    add     0x1, r2
.L.start_PE0.1:
    andi    0xffff, r2, tp
    ori     0x9c40, r0, r6
    cmp     r6, tp
    blt    .L.start_PE0.0

$endif  ; ENABLE_PE1_BY_PE0

$if ENABLE_PE2_BY_PE0 == FLAG_ON
    ld.w    0xfffb2000[r0], r10     ; get BOOTCTRL
    ori     4, r10, r11             ; set 1 in BOOTCTRL.BC2 for enabled PE2
    st.w    r11, 0xfffb2000[r0]     ; set BOOTCTRL

    mov     0x0, r2                 ; wait for 100us(0x9c40(40,000)count)
    br     .L.start_PE0.3
.L.start_PE0.2:
    add     0x1, r2
.L.start_PE0.3:
    andi    0xffff, r2, tp
    ori     0x9c40, r0, r6
    cmp     r6, tp
    blt    .L.start_PE0.2

$endif  ; ENABLE_PE2_BY_PE0

$if ENABLE_PE3_BY_PE0 == FLAG_ON
    ld.w    0xfffb2000[r0], r10     ; get BOOTCTRL
    ori     8, r10, r11             ; set 1 in BOOTCTRL.BC3 for enabled PE3
    st.w    r11, 0xfffb2000[r0]     ; set BOOTCTRL

$endif  ; ENABLE_PE3_BY_PE0

    jarl    _hdwinit_PE0, lp        ; initialize hardware

$if USE_TABLE_REFERENCE_METHOD == FLAG_ON
    jarl    _init_eiint, lp         ; initialize exception
$endif  ; USE_TABLE_REFERENCE_METHOD

    mov     #_pm0_setting_table, r13
    ld.w    .OFFSET_ENTRY[r13], r10 ; set __start_pm0 addresss
    ldsr    r10, 2, 0               ; set FEPC

;    jump to __start_pm0
    feret

;-----------------------------------------------------------------------------
;   __start_PE1
;-----------------------------------------------------------------------------

$if ENABLE_PE1_BY_PE0 == FLAG_ON
__start_PE1:
    jarl    _hdwinit_PE1, lp        ; initialize hardware

$if USE_TABLE_REFERENCE_METHOD == FLAG_ON
    jarl    _init_eiint, lp         ; initialize exception
$endif  ; USE_TABLE_REFERENCE_METHOD

    mov     #_pm1_setting_table, r13
    ld.w    .OFFSET_ENTRY[r13], r10 ; set __start_pm1 addresss
    ldsr    r10, 2, 0               ; set FEPC

;    jump to __start_pm1
    feret
$endif  ; ENABLE_PE1_BY_PE0

    br      __exit

;-----------------------------------------------------------------------------
;   __start_PE2
;-----------------------------------------------------------------------------

$if ENABLE_PE2_BY_PE0 == FLAG_ON
__start_PE2:
    jarl    _hdwinit_PE2, lp        ; initialize hardware

$if USE_TABLE_REFERENCE_METHOD == FLAG_ON
    jarl    _init_eiint, lp         ; initialize exception
$endif  ; USE_TABLE_REFERENCE_METHOD

    mov     #_pm2_setting_table, r13
    ld.w    .OFFSET_ENTRY[r13], r10 ; set __start_pm2 addresss
    ldsr    r10, 2, 0               ; set FEPC

;    jump to __start_pm2
    feret
$endif  ; ENABLE_PE2_BY_PE0

    br      __exit

;-----------------------------------------------------------------------------
;   __start_PE3
;-----------------------------------------------------------------------------

$if ENABLE_PE3_BY_PE0 == FLAG_ON
__start_PE3:
    jarl    _hdwinit_PE3, lp        ; initialize hardware

$if USE_TABLE_REFERENCE_METHOD == FLAG_ON
    jarl    _init_eiint, lp         ; initialize exception
$endif  ; USE_TABLE_REFERENCE_METHOD

    mov     #_pm3_setting_table, r13
    ld.w   .OFFSET_ENTRY[r13], r10  ; set __start_pm3 addresss
    ldsr    r10, 2, 0               ; set FEPC

;    jump to __start_pm3
    feret
$endif  ; ENABLE_PE3_BY_PE0

    br      __exit

;-----------------------------------------------------------------------------
;   _hdwinit_PE0
;-----------------------------------------------------------------------------

    .section    ".text", text
    .align      4

_hdwinit_PE0:
    mov     lp, r14                 ; save return address

    ; clear Cluster RAM0
    mov     CLUSTER_RAM0_ADDR0, r6
    mov     CLUSTER_RAM0_END0, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM2
    mov     CLUSTER_RAM2_ADDR0, r6
    mov     CLUSTER_RAM2_END0, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM3
    mov     CLUSTER_RAM3_ADDR0, r6
    mov     CLUSTER_RAM3_END0, r7
    jarl    _zeroclr4, lp

    ; clear Local RAM(CPU0)
    mov     LOCAL_RAM_CPU0_ADDR, r6
    mov     LOCAL_RAM_CPU0_END, r7
    jarl    _zeroclr4, lp

    ; finish the clock gearup seaquence
    mov     MEV_ADDR, r10
    set1    4, [r10]

.L.hdwinit_PE0.0:

    mov     MEV_ADDR, r10
    set1    0, [r10]                ; Bit0 indicate PE0 wait for PEx

$if ENABLE_PE1_BY_PE0 == FLAG_ON
    ; wait for PE1
.L.hdwinit_PE0.1:
    tst1    1, [r10]                ; Bit1 indicate PE1 wait for PE0
    bnz    .L.hdwinit_PE0.2
    snooze
    br     .L.hdwinit_PE0.1
$endif  ; ENABLE_PE1_BY_PE0

.L.hdwinit_PE0.2:

$if ENABLE_PE2_BY_PE0 == FLAG_ON
    ; wait for PE2
.L.hdwinit_PE0.3:
    tst1    2, [r10]                ; Bit2 indicate PE2 wait for PE0
    bnz    .L.hdwinit_PE0.4
    snooze
    br     .L.hdwinit_PE0.3
$endif  ; ENABLE_PE2_BY_PE0

.L.hdwinit_PE0.4:

$if ENABLE_PE3_BY_PE0 == FLAG_ON
    ; wait for PE3
.L.hdwinit_PE0.5:
    tst1    3, [r10]                ; Bit3 indicate PE3 wait for PE0
    bnz    .L.hdwinit_PE0.6
    snooze
    br     .L.hdwinit_PE0.5
$endif  ; ENABLE_PE3_BY_PE0

.L.hdwinit_PE0.6:

    mov     r14, lp
    jmp     [lp]

;-----------------------------------------------------------------------------
;   _hdwinit_PE1
;-----------------------------------------------------------------------------

    .section    ".text", text
    .align      4

_hdwinit_PE1:
    mov     lp, r14                 ; save return address

    ; clear Cluster RAM0
    mov     CLUSTER_RAM0_ADDR1, r6
    mov     CLUSTER_RAM0_END1, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM2
    mov     CLUSTER_RAM2_ADDR1, r6
    mov     CLUSTER_RAM2_END1, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM3
    mov     CLUSTER_RAM3_ADDR1, r6
    mov     CLUSTER_RAM3_END1, r7
    jarl    _zeroclr4, lp

    ; clear Local RAM(CPU1)
    mov     LOCAL_RAM_CPU1_ADDR, r6
    mov     LOCAL_RAM_CPU1_END, r7
    jarl    _zeroclr4, lp

    ; wait for PE0
    mov     MEV_ADDR, r10

.L.hdwinit_PE1.0:
    tst1    4, [r10]                ; Check the value of bit 4 of MEV_ADDR
    bnz    .L.hdwinit_PE1.1
    snooze
    br     .L.hdwinit_PE1.0

.L.hdwinit_PE1.1:
    mov     MEV_ADDR, r10
    set1    1, [r10]                ; Bit1 indicate PE1 wait for PEx

    ; wait for PE0
.L.hdwinit_PE1.2:
    tst1    0, [r10]                ; Bit0 indicate PE0 wait for PE1
    bnz    .L.hdwinit_PE1.3
    snooze
    br     .L.hdwinit_PE1.2

.L.hdwinit_PE1.3:

$if ENABLE_PE2_BY_PE0 == FLAG_ON
    ; wait for PE2
.L.hdwinit_PE1.4:
    tst1    2, [r10]                ; Bit2 indicate PE2 wait for PE1
    bnz    .L.hdwinit_PE1.5
    snooze
    br     .L.hdwinit_PE1.4
$endif  ; ENABLE_PE2_BY_PE0

.L.hdwinit_PE1.5:

$if ENABLE_PE3_BY_PE0 == FLAG_ON
    ; wait for PE3
.L.hdwinit_PE1.6:
    tst1    3, [r10]                ; Bit3 indicate PE3 wait for PE1
    bnz    .L.hdwinit_PE1.7
    snooze
    br     .L.hdwinit_PE1.6
$endif  ; ENABLE_PE3_BY_PE0

.L.hdwinit_PE1.7:
    mov     r14, lp
    jmp     [lp]

;-----------------------------------------------------------------------------
;   _hdwinit_PE2
;-----------------------------------------------------------------------------

    .section    ".text", text
    .align      4

_hdwinit_PE2:
    mov     lp, r14                 ; save return address

    ; clear Cluster RAM1
    mov     CLUSTER_RAM1_ADDR2, r6
    mov     CLUSTER_RAM1_END2, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM2
    mov     CLUSTER_RAM2_ADDR2, r6
    mov     CLUSTER_RAM2_END2, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM3
    mov     CLUSTER_RAM3_ADDR2, r6
    mov     CLUSTER_RAM3_END2, r7
    jarl    _zeroclr4, lp

    ; clear Local RAM(CPU2)
    mov     LOCAL_RAM_CPU2_ADDR, r6
    mov     LOCAL_RAM_CPU2_END, r7
    jarl    _zeroclr4, lp

    ; wait for PE0
    mov     MEV_ADDR, r10

.L.hdwinit_PE2.0:
    tst1    4, [r10]                ; Check the value of bit 4 of MEV_ADDR
    bnz    .L.hdwinit_PE2.1
    snooze
    br     .L.hdwinit_PE2.0

.L.hdwinit_PE2.1:
    mov     MEV_ADDR, r10
    set1    2, [r10]                ; Bit2 indicate PE2 wait for PEx

    ; wait for PE0
.L.hdwinit_PE2.2:
    tst1    0, [r10]                ; Bit0 indicate PE0 wait for PE2
    bnz    .L.hdwinit_PE2.3
    snooze
    br     .L.hdwinit_PE2.2

.L.hdwinit_PE2.3:

$if ENABLE_PE1_BY_PE0 == FLAG_ON
    ; wait for PE1
.L.hdwinit_PE2.4:
    tst1    1, [r10]                ; Bit1 indicate PE1 wait for PE2
    bnz    .L.hdwinit_PE2.5
    snooze
    br     .L.hdwinit_PE2.4
$endif  ; ENABLE_PE1_BY_PE0

.L.hdwinit_PE2.5:

$if ENABLE_PE3_BY_PE0 == FLAG_ON
    ; wait for PE3
.L.hdwinit_PE2.6:
    tst1    3, [r10]                ; Bit3 indicate PE3 wait for PE2
    bnz    .L.hdwinit_PE2.7
    snooze
    br     .L.hdwinit_PE2.6
$endif  ; ENABLE_PE3_BY_PE0

.L.hdwinit_PE2.7:
    mov     r14, lp
    jmp     [lp]

;-----------------------------------------------------------------------------
;   _hdwinit_PE3
;-----------------------------------------------------------------------------

    .section    ".text", text
    .align      4

_hdwinit_PE3:
    mov     lp, r14                 ; save return address

    ; clear Cluster RAM1
    mov     CLUSTER_RAM1_ADDR3, r6
    mov     CLUSTER_RAM1_END3, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM2
    mov     CLUSTER_RAM2_ADDR3, r6
    mov     CLUSTER_RAM2_END3, r7
    jarl    _zeroclr4, lp

    ; clear Cluster RAM3
    mov     CLUSTER_RAM3_ADDR3, r6
    mov     CLUSTER_RAM3_END3, r7
    jarl    _zeroclr4, lp

    ; clear Local RAM(CPU3)
    mov     LOCAL_RAM_CPU3_ADDR, r6
    mov     LOCAL_RAM_CPU3_END, r7
    jarl    _zeroclr4, lp

    ; wait for PE0
    mov     MEV_ADDR, r10

.L.hdwinit_PE3.0:
    tst1    4, [r10]                ; Check the value of bit 4 of MEV_ADDR
    bnz    .L.hdwinit_PE3.1
    snooze
    br     .L.hdwinit_PE3.0

.L.hdwinit_PE3.1:
    mov     MEV_ADDR, r10
    set1    3, [r10]                ; Bit3 indicate PE3 wait for PEx

    ; wait for PE0
.L.hdwinit_PE3.2:
    tst1    0, [r10]                ; Bit0 indicate PE0 wait for PE3
    bnz    .L.hdwinit_PE3.3
    snooze
    br     .L.hdwinit_PE3.2

.L.hdwinit_PE3.3:

$if ENABLE_PE1_BY_PE0 == FLAG_ON
    ; wait for PE1
.L.hdwinit_PE3.4:
    tst1    1, [r10]                ; Bit1 indicate PE1 wait for PE3
    bnz    .L.hdwinit_PE3.5
    snooze
    br     .L.hdwinit_PE3.4
$endif  ; ENABLE_PE1_BY_PE0

.L.hdwinit_PE3.5:

$if ENABLE_PE2_BY_PE0 == FLAG_ON
    ; wait for PE2
.L.hdwinit_PE3.6:
    tst1    2, [r10]                ; Bit2 indicate PE2 wait for PE3
    bnz    .L.hdwinit_PE3.7
    snooze
    br     .L.hdwinit_PE3.6
$endif  ; ENABLE_PE2_BY_PE0

.L.hdwinit_PE3.7:
    mov     r14, lp
    jmp     [lp]

;-----------------------------------------------------------------------------
;   _clock_gearup
;-----------------------------------------------------------------------------

    .align    4
_clock_gearup:

.L.clock_gearup.0:
    ld.w    0xff980004[r0], r2      ; get PLLS
    andi    0x3, r2, r2
    cmp     0x3, r2
    bnz    .L.clock_gearup.0

    mov     -0x5a5a5aff, r2         ; set 0xA5A5A501 in CLKKCPROT1 for enable writes to protected registers
    st.w    r2, 0xff980700[r0]      ; set CLKKCPROT1

    ld.w    0xff980120[r0], r2      ; get CLKD_PLLC
    ori     0x2, r2, r2             ; set 2 in CLKD_PLLC.PLLCLKDCSID for clock divided by 2
    mov     -0x6, r6
    and     r6, r2
    st.w    r2, 0xff980120[r0]      ; set CLKD_PLLC

.L.clock_gearup.1:
    ld.w    0xff980128[r0], r2      ; get CLKD_PLLS
    andi    0x2, r2, r0             ; confirm that the value of CLKD_PLLS.PLLCLKDSYNC is not 1
    bz     .L.clock_gearup.1        ; if the CLKD_PLLS.PLLCLKDSYNC is not 1, repeat execution

    mov     0x0, r2                 ; wait for 100us(0x9c40(40,000)count).
    br     .L.clock_gearup.3
.L.clock_gearup.2:
    add     0x1, r2
.L.clock_gearup.3:
    andi    0xffff, r2, tp
    ori     0x9c40, r0, r6
    cmp     r6, tp
    blt    .L.clock_gearup.2

    ld.w    0xff980100[r0], r2      ; get CKSC_CPUC
    mov     -0x2, r6                ; set 0 in CKSC_CPUC.CPUCLKSCSID in clock source control is CLK_PLLO
    and     r6, r2
    st.w    r2, 0xff980100[r0]      ; set CKSC_CPUC

.L.clock_gearup.4:
    ld.w    0xff980108[r0], r2      ; get CKSC_CPUS
    andi    0x1, r2, r0             ; confirm that the value of CKSC_CPUS.CPUCLKSACT is 1
    bnz    .L.clock_gearup.4        ; if the CKSC_CPUS.CPUCLKSACT is not 1, repeat execution

    mov     0x0, r2                 ; wait for 100us(0x9c40(40,000)count).
    br     .L.clock_gearup.6
.L.clock_gearup.5:
    add     0x1, r2
.L.clock_gearup.6:
    andi    0xffff, r2, tp
    ori     0x9c40, r0, r6
    cmp     r6, tp
    blt    .L.clock_gearup.5

    ld.w    0xff980120[r0], r2      ; get CLKD_PLLC
    ori     0x1, r2, r2             ; set 1 in CLKD_PLLC.PLLCLKDCSID for no division
    mov     -0x7, r6
    and     r6, r2
    st.w    r2, 0xff980120[r0]      ; set CLKD_PLLC


.L.clock_gearup.7:
    ld.w    0xff980128[r0], r2      ; get CLKD_PLLS
    andi    0x2, r2, r0             ; confirm that the value of CLKD_PLLS.PLLCLKDSYNC is not 1
    bz     .L.clock_gearup.7        ; if the CLKD_PLLS.PLLCLKDSYNC is not 1, repeat execution

    mov     0x0, r2                 ; wait for 100us(0x9c40(40,000)count).
    br     .L.clock_gearup.9
.L.clock_gearup.8:
    add     0x1, r2
.L.clock_gearup.9:
    andi    0xffff, r2, tp
    ori     0x9c40, r0, r6
    cmp     r6, tp
    blt    .L.clock_gearup.8

    mov     -0x5a5a5b00, r2         ; set 0xA5A5A500 in CLKKCPROT1 for disable writes to protected registers
    st.w    r2, 0xff980700[r0]      ; set CLKKCPROT1

    jmp    [lp]

;-----------------------------------------------------------------------------
;   _module_standby_set
;-----------------------------------------------------------------------------

    .align    4
_module_standby_set:

    mov     -0x5a5a5aff, r2         ; set 0xA5A5A501 in MSRKCPROT for enables write access of protected registers
    st.w    r2, 0xFF981710[r0]      ; set MSRKCPROT

    ; RS-CANFD
    st.w    r0, 0xFF981000[r0]      ; set MSR_RSCFD (RS-CANFD8-15 is operating and RS-CANFD0-7 is operating)
;    mov     r2, 0x3                 ; set 1 in MSR_RCAN.MS_RCAN1 for All clocks connected to RS-CANFD8-15 are stopped
                                     ; set 1 in MSR_RCAN.MS_RCAN0 for All clocks connected to RS-CANFD0-7 are stopped
;    st.w    r2, 0xFF981000[r0]      ; set MSR_RSCFD

    mov     -0x5a5a5a00, r2         ; set 0xA5A5A500 in MSRKCPROT for disables write access of protected registers
    st.w    r2, 0xFF981710[r0]      ; set MSRKCPROT

    jmp    [lp]

;-----------------------------------------------------------------------------
;   zeroclr4
;-----------------------------------------------------------------------------

    .align    4
_zeroclr4:
    br      .L.zeroclr4.2
.L.zeroclr4.1:
    st.w    r0, [r6]
    add     4, r6
.L.zeroclr4.2:
    cmp     r6, r7
    bh      .L.zeroclr4.1
    jmp	[lp]

;-----------------------------------------------------------------------------
;   init_eiint
;-----------------------------------------------------------------------------

$if USE_TABLE_REFERENCE_METHOD == FLAG_ON
    ; interrupt control register address
    ICBASE  .set    0xFFFC0000

    .align      4

_init_eiint:

    stsr    0, r10, 2               ; get PEID.PEID

    cmp     0, r10
    bnz    .L.init_eiint.1          ; if PEID.PEID is not 0
    mov     #_INT_Vectors_PE0, r10
    ldsr    r10, 4, 1               ; set INTBP
    br     .L.init_eiint.4

.L.init_eiint.1:
$if ENABLE_PE1_BY_PE0 == FLAG_ON
    cmp     1, r10
    bnz    .L.init_eiint.2          ; if PEID.PEID is not 1
    mov     #__sEIINTTBL_PE1, r10
    ldsr    r10, 4, 1               ; set INTBP
    br     .L.init_eiint.4
$endif  ; ENABLE_PE1_BY_PE0

.L.init_eiint.2:
$if ENABLE_PE2_BY_PE0 == FLAG_ON
    cmp     2, r10
    bnz    .L.init_eiint.3          ; if PEID.PEID is not 2
    mov     #__sEIINTTBL_PE2, r10
    ldsr    r10, 4, 1               ; set INTBP
    br     .L.init_eiint.4
$endif  ; ENABLE_PE2_BY_PE0

.L.init_eiint.3:
$if ENABLE_PE3_BY_PE0 == FLAG_ON
    cmp     3, r10
    bnz    .L.init_eiint.5          ; if PEID.PEID is not 3
    mov     #__sEIINTTBL_PE3, r10
    ldsr    r10, 4, 1               ; set INTBP
    br     .L.init_eiint.4
$endif  ; ENABLE_PE3_BY_PE0

.L.init_eiint.4:
    ; some inetrrupt channels use the table reference method.
    mov     ICBASE, r10     ; get interrupt control register address
    set1    6, 0[r10]       ; set INT0 as table reference
    set1    6, 2[r10]       ; set INT1 as table reference
    set1    6, 4[r10]       ; set INT2 as table reference
    set1    6, 6[r10]       ; set INT3 as table reference
    set1    6, 8[r10]       ; set INT4 as table reference
    set1    6,10[r10]       ; set INT5 as table reference
    set1    6,12[r10]       ; set INT6 as table reference
    set1    6,14[r10]       ; set INT7 as table reference
    set1    6,16[r10]       ; set INT8 as table reference

.L.init_eiint.5:
    jmp     [lp]
$endif

